| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- /**
- * 根据给定的mesh数据/纹理/材质,渲染出结果
- */
- import {
- _decorator,
- CCBoolean,
- Component,
- EffectAsset,
- Material,
- Mesh,
- MeshRenderer,
- Node,
- SpriteFrame,
- Texture2D,
- UIMeshRenderer,
- utils,
- v3,
- v4,
- Vec3,
- } from 'cc';
- import earcut from './EarCut';
- const { ccclass, property, executeInEditMode, menu } = _decorator;
- @ccclass('MeshSprite')
- @executeInEditMode
- @menu('2D/MeshSprite(Mesh精灵)')
- export class MeshSprite extends Component {
- @property(EffectAsset)
- private _effectAsset: EffectAsset = null!;
- @property({
- type: EffectAsset,
- tooltip: '渲染effectAssets文件,拖入curvetexture-sprite即可',
- displayName: 'effect asset文件',
- })
- public get effectAsset(): EffectAsset {
- return this._effectAsset;
- }
- public set effectAsset(value: EffectAsset) {
- if (value !== this._effectAsset) {
- this._mat?.destroy();
- this._mat = null;
- this._effectAsset?.destroy();
- this._effectAsset = value;
- this._refreshAll();
- }
- }
- @property(SpriteFrame)
- private _spriteFrame: SpriteFrame = null!;
- @property({
- type: SpriteFrame,
- tooltip: '纹理文件,拖入spriteframe即可',
- displayName: '纹理文件',
- })
- get spriteFrame(): SpriteFrame {
- return this._spriteFrame;
- }
- set spriteFrame(value: SpriteFrame) {
- if (this._spriteFrame !== value) {
- this._spriteFrame = value;
- if (value) {
- if (
- (value.originalSize.width & (value.originalSize.width - 1)) !== 0 ||
- (value.originalSize.height & (value.originalSize.height - 1)) !== 0
- ) {
- console.warn(`纹理尺寸(${value.originalSize.width}x${value.originalSize.height})不是2的幂,请修改。`);
- return;
- }
- }
- if (this._spriteFrame) {
- this._curve_width = this._spriteFrame.originalSize.width;
- this._curve_height = this._spriteFrame.originalSize.height;
- }
- this._refreshAll();
- }
- }
- @property({})
- private _updownFix: boolean = false;
- @property({
- tooltip: `是否上下翻转纹理,默认false`,
- displayName: `是否上下翻转`,
- })
- get updownFix() {
- return this._updownFix;
- }
- set updownFix(value) {
- this._updownFix = value;
- this._refreshAll();
- }
- private _meshRender: MeshRenderer = null;
- private _uiMeshRender: UIMeshRenderer = null;
- private _mat: Material = null;
- private _vertexes: Vec3[] = [
- v3(-200, 200, 0), // 左上
- v3(-200, -200, 0), // 左下
- v3(200, -200, 0), // 右下
- v3(200, 200, 0), // 右上
- ];
- private _curve_width = 0;
- private _curve_height = 0;
- private _uvs: number[] = [];
- protected onEnable(): void {
- this._refreshAll();
- }
- public setVertexes(vertexes: Vec3[]) {
- this._vertexes = vertexes;
- this._refreshAll();
- }
- private _refreshAll() {
- if (!this._spriteFrame) {
- console.warn(`没有spriteFrame,请拖入纹理`);
- return;
- }
- if (!this._effectAsset) {
- console.warn(`没有effectAsset,请拖入effect文件 curvetexture-sprite`);
- return;
- }
- this._meshRender = this.node.getComponent(MeshRenderer);
- if (!this._meshRender) {
- this._meshRender = this.node.addComponent(MeshRenderer);
- }
- this._uiMeshRender = this.node.getComponent(UIMeshRenderer);
- if (!this._uiMeshRender) {
- this._uiMeshRender = this.node.addComponent(UIMeshRenderer);
- }
- this._mat = this._meshRender.getMaterialInstance(0) as Material;
- if (!this._mat) {
- this._mat = new Material();
- this._mat.initialize({
- effectAsset: this._effectAsset,
- defines: {
- USE_TEXTURE: true,
- },
- });
- this._meshRender.setMaterialInstance(this._mat, 0);
- }
- this._spriteFrame.texture.setWrapMode(
- Texture2D.WrapMode.REPEAT,
- Texture2D.WrapMode.REPEAT,
- Texture2D.WrapMode.REPEAT
- );
- this._curve_width = this._spriteFrame.originalSize.width;
- this._curve_height = this._spriteFrame.originalSize.height;
- this._mat.setProperty('mainTexture', this._spriteFrame.texture, 0);
- const uv = this._spriteFrame.uv;
- const uv_x = uv[0]; // ul
- const uv_y = uv[1]; // vb
- const uv_w = uv[6] - uv[0]; // ur - ul
- const uv_h = uv[5] - uv[1]; // vt - vb
- const altlasUV = v4(uv_x, uv_y, uv_w, uv_h);
- // console.log(this.node.name + ' altlasUV', altlasUV);
- this._mat.setProperty('altlasUV', altlasUV, 0);
- const positions: number[] = [];
- // const positions2d: number[] = [];
- for (let i = 0; i < this._vertexes.length; i++) {
- const v = this._vertexes[i];
- positions.push(v.x, v.y, v.z);
- // positions2d.push(v.x, v.y);
- }
- // if (this._uvs.length <= 8) {
- this._uvs = this._calculateUVs();
- // }
- const start = performance.now();
- const indices: number[] = earcut(positions, null, 3);
- const end = performance.now();
- // console.log(`earcut triangulation 解析转换为渲染三角形索引耗时 took ${(end - start).toFixed(2)} ms`);
- // console.log(this.node.name + ' indices ', indices);
- let mesh = utils.MeshUtils.createMesh({
- positions: positions,
- uvs: this._uvs,
- indices: indices,
- });
- if (this._meshRender!.mesh) {
- this._meshRender!.mesh.destroy();
- }
- this._meshRender!.mesh = mesh;
- }
- private _calculateUVs() {
- let uvs: number[] = [];
- if (!this._spriteFrame || this._vertexes.length === 0) {
- return uvs;
- }
- for (let i = 0; i < this._vertexes.length; i++) {
- const d = this._vertexes[i];
- const u = d.x / this._curve_width;
- let v = 1.0 - d.y / this._curve_height;
- if (this._updownFix) {
- v = d.y / this._curve_height;
- }
- uvs.push(u, v);
- }
- return uvs;
- }
- }
|